home *** CD-ROM | disk | FTP | other *** search
- /*
- * Blob Manager Demonstration: library routines
- */
-
- # include "BlobMgr.h"
- # include "BlobDemo.h"
-
-
- static short charBlobSize = 18;
-
- /*
- * StrCpy copies the second argument into the first.
- * StrCat appends the second argument to the first.
- *
- * Both assume Pascal-style strings.
- */
-
-
- void
- StrCpy (StringPtr dst, StringPtr src)
- {
- short i;
-
- for (i = 0; i <= src[0]; ++i)
- dst[i] = src[i];
- }
-
-
- void
- StrCat (StringPtr dst, StringPtr src)
- {
- short i, dlen, slen;
-
- slen = src[0];
- dlen = dst[0];
- for (i = 1; slen > 0; ++i, --slen)
- dst[dlen + i] = src[i];
- dst[0] += src[0];
- }
-
-
- /*
- * MovesLeft creates a string that says "n Moves Left"
- */
-
- void
- MovesLeft (short n, StringPtr s)
- {
- NumToString (n, s);
- StrCat (s, (n == 1 ? "\p Move Left" : "\p Moves Left"));
- }
-
-
- /*
- * Draw vertical button blob. It's assumed the font to draw in is the
- * current font.
- *
- * The static region (the button frame) is not drawn gray when the button
- * is unhilited (unlike most blobs), to simulate behavior of regular push
- * buttons. For this reason, the bProcManualDimMask flag is set in the flags word.
- */
-
- static pascal void
- DrawVButtonBlob (BlobHandle bDst, BlobHandle bSrc, short partCode)
- {
- StringHandle hStr;
- StringPtr title;
- FontInfo fInfo;
- Rect r;
- RGBColor gray;
- short cHeight; /* character height */
- short tHeight; /* title height */
- short h, v;
- short i;
- short savedTextMode;
-
- if (partCode == inStatBlob) /* draw frame */
- {
- FrameRgn ((**bDst).statRgn);
- }
- else /* draw text inside frame */
- {
- /*
- * Draw text of source blob in the drag region of the
- * destination blob
- */
- FillRgn ((**bDst).dragRgn, white);
- hStr = (StringHandle) GetBRefCon (bSrc); /* text from source */
- if (hStr == (StringHandle) nil)
- return;
- HLock ((Handle) hStr);
- title = *hStr;
- GetFontInfo (&fInfo);
- cHeight = fInfo.ascent + fInfo.descent;
- tHeight = title[0] * (cHeight + fInfo.leading) - fInfo.leading;
- r = BDragBox (bDst); /* drag box of dest */
- v = (r.top + r.bottom - tHeight ) / 2 + fInfo.ascent;
- /*
- * Check whether to draw in gray or not. If so, and RGB gray is
- * available, set the transfer mode.
- */
- if (GetBDrawMode (bDst, partCode) == dimDraw)
- (void) BeginBlobDimDraw (bDst, partCode);
- for (i = 1; i <= title[0]; ++i)
- {
- h = (r.left + r.right - CharWidth (title[i])) / 2;
- MoveTo (h, v);
- DrawChar (title[i]);
- v += cHeight + fInfo.leading;
- }
- if (GetBDrawMode (bDst, partCode) == dimDraw)
- EndBlobDimDraw ();
- HUnlock ((Handle) hStr);
- }
- }
-
-
- /*
- * Make a simulated push button. It looks like a regular button,
- * except that it's oriented vertically rather than horizontally.
- * bSet is the blob set to add the button blob to, r defines the
- * bounds rect, and title is a string containing the text to be drawn
- * in the blob.
- * The title is copied into a new handle and the handle is stored into
- * the blob's reference constant so the draw proc can tell what to draw
- * later.
- *
- * The glueMax and mustMatch fields are assumed to be zero and false.
- */
-
- BlobHandle
- NewVButtonBlob (BlobSetHandle bSet, Rect *r, StringPtr title,
- Boolean visible)
- {
- BlobHandle b;
- StringHandle hStr;
- RgnHandle rgn, rgn2;
-
- /*
- * Make the regions defining the blob first. The drag region is inset
- * by one so that the text in the middle can be dimmed without dimming
- * the frame.
- */
-
- rgn = NewRgn ();
- OpenRgn ();
- FrameRoundRect (r, 10, 10); /* 12 ? */
- CloseRgn (rgn);
- rgn2 = NewRgn ();
- CopyRgn (rgn, rgn2);
- InsetRgn (rgn2, 1, 1);
-
- /* Now make the blob and define its image */
-
- hStr = (StringHandle) NewHandle (title[0] + 1);
- HLock ((Handle) hStr);
- StrCpy (*hStr, title);
- HUnlock ((Handle) hStr);
- b = NewBlob (bSet, visible, 0, false, (long) hStr);
- SetProcRgnBlob (b, DrawVButtonBlob, rgn2, rgn);
- SetBlobFlags (b, bProcManualDimMask); /* draw proc does own dimming */
- DisposeRgn (rgn);
- DisposeRgn (rgn2);
- return (b);
- }
-
-
- /*
- * Drawing proc for character blobs. The drag region covers the entire
- * blob, so the drag region is actually empty. Thus the drawing procedure
- * only looks at the drag region.
- */
-
- static pascal void
- DrawCharBlob (BlobHandle bDst, BlobHandle bSrc, short partCode)
- {
- GrafPtr port;
- Boolean canDrawGray;
- short savedTextMode;
- Rect r;
- char c;
- short h, v;
-
- if (partCode == inStatBlob) /* irrelevant, since empty */
- return;
-
- r = BDragBox (bDst);
- c = (char) LoWord (GetBRefCon (bSrc));
- EraseRoundRect (&r, 10, 10);
- if (c == ' ')
- {
- FrameRoundRect (&r, 10, 10);
- }
- else
- {
- h = (r.left + r.right - CharWidth (c)) / 2;
- v = r.bottom - 4;
- MoveTo (h, v);
- DrawChar (c);
- }
- }
-
-
- /*
- * Make a blob with a character in the middle (or a frame if the
- * character is a space). Pass all the normal NewBlob parameters
- * except the reference constant, plus the horizontal and vertical
- * coordinates, and the character to be drawn in the blob.
- *
- * The char is stored as the low word of the reference value. The
- * application can put whatever it wants in the high word.
- */
-
- BlobHandle
- MakeCharBlob (BlobSetHandle bSet, Boolean enable, short glueMVal,
- Boolean mustMatch, short h, short v, char c)
- {
- BlobHandle b;
- Rect r;
-
- /*
- * Make the regions defining the blob first. The drag region is inset
- * by one so that the text in the middle can be dimmed without dimming
- * the frame.
- */
-
- SetRect (&r, h, v, h + charBlobSize, v + charBlobSize);
-
- b = NewBlob (bSet, enable, glueMVal, mustMatch, (long) c);
- SetProcRectBlob (b, DrawCharBlob, &r, &r);
- return (b);
- }
-
-
- /*
- * Set the size in which character blobs are created
- */
-
- void
- SetCharBlobSize (short size)
- {
- charBlobSize = size;
- }
-
-
- /*
- * Determine the rectangle that defines each element of a grid,
- * and pass the rectangle to a blob-drawing proc. The proc draws
- * whatever goes into the element. Creates blobs a row at a time.
- */
-
- void
- MakeBlobGrid (short rows, short cols, short hOff, short vOff,
- short hWidth, short vHeight, short hGap, short vGap,
- void (*p) (Rect *r))
- {
- short i, j;
- short h, v;
- Rect r;
-
- for (j = 0; j < rows; ++j)
- {
- for (i = 0; i < cols; ++i)
- {
- h = hOff + i * (hGap + hWidth);
- v = vOff + j * (vGap + vHeight);
- SetRect (&r, h, v, h + hWidth, v + vHeight);
- (*p) (&r);
- }
- }
- }
-
-
- /*
- * Draw a grid with the given number of rows and columns. The upper
- * left-hand corner of the top element is at (hoff, voff). The
- * height and width of each element is vHeight and hWidth. The horizontal
- * and vertical gaps between elements are hGap and vGap. A border is
- * also drawn around the whole grid.
- */
-
- void
- DrawGrid (short rows, short cols, short hOff, short vOff,
- short hWidth, short vHeight, short hGap, short vGap)
- {
- short i;
- short h, v;
- short len;
- Rect r;
-
- hOff -= hGap;
- vOff -= vGap;
- PenSize (hGap, vGap);
- /* draw vertical lines */
- len = rows * (vGap + vHeight);
- for (i = 0; i <= cols; ++i)
- {
- h = hOff + i * (hGap + hWidth);
- MoveTo (h, vOff);
- LineTo (h, vOff + len);
- }
- /* draw horizontal lines */
- len = cols * (hGap + hWidth);
- for (i = 0; i <= rows; ++i)
- {
- v = vOff + i * (vGap + vHeight);
- MoveTo (hOff, v);
- LineTo (hOff + len, v);
- }
- PenNormal ();
- }
-
-
- /*
- * Routines to create or dispose of offscreen ports
- */
-
- GrafPtr
- NewOffPort (Rect *r)
- {
- GrafPtr thePort, tmpPort;
- BitMap *theMap;
- long bitCount;
- short rowBytes;
- Ptr bits;
-
- rowBytes = ((r->right - r->left + 15) / 8) & (~1);
- bitCount = rowBytes * (r->bottom - r->top);
- bits = NewPtr (bitCount);
- if (bits)
- {
- thePort = (GrafPtr) NewPtr ((long) sizeof (GrafPort));
- if (thePort)
- {
- theMap = (BitMap *) NewPtr ((long) sizeof (BitMap));
- if (theMap)
- {
- theMap->bounds = *r;
- theMap->rowBytes = rowBytes;
- theMap->baseAddr = bits;
- GetPort (&tmpPort);
- OpenPort (thePort);
- SetPortBits (theMap);
- PortSize (r->right - r->left, r->bottom - r->top);
- RectRgn (thePort->visRgn, &thePort->portRect);
- ClipRect (&thePort->portRect);
- EraseRect (&thePort->portRect);
- SetPort (tmpPort);
- return (thePort);
- }
- DisposPtr ((Ptr) thePort);
- }
- DisposPtr (bits);
- }
- return (nil);
- }
-
-
- void
- DisposeOffPort (GrafPtr thePort)
- {
- ClosePort (thePort);
- DisposPtr (thePort->portBits.baseAddr);
- DisposPtr ((Ptr) &thePort->portBits);
- DisposPtr ((Ptr) thePort);
- }
-
-
- /*
- * Board position drawing procedure. All positions are drawn the
- * same - a black rectangle. However, the unused positions are set
- * dimmed by InitBoard, so the drawing mechanisms make them gray.
- * For the drag region of used positions,
- * this proc is only called if the position has no piece (i.e., no
- * glob) because the pieces are picture blobs.
- *
- * For these reasons, bSrc and bDst are always equal when
- * DrawBoardPos is called.
- */
-
- static pascal void
- DrawBoardPos (BlobHandle bDst, BlobHandle bSrc, short partCode)
- {
- Rect r;
-
- r = BStatBox (bDst);
- PaintRect (&r);
- }
-
-
- /*
- * Build a checkerboard, which consists of alternating black and gray
- * squares. They are actually the same as far as the drawing proc
- * goes, but the gray squares are set to be dimmed so that the
- * normal drawing mechanisms do the work of making the two types
- * of square look distinct. The fact that the gray squares are
- * dimmed also makes the hit-testing mechanisms ignore them.
- */
-
- void
- MakeCheckerBoard (BlobSetHandle *boardBlobs, CheckerBoard *board, short pieceSize)
- {
- short h, v;
- Rect r, r2;
- BlobHandle b;
-
- *boardBlobs = NewBlobSet ();
- for (v = 0; v < 8; v++)
- {
- for (h = 0; h < 8; h++)
- {
- b = NewBlob (*boardBlobs, true, 0, false, 0L);
- (*board)[h][v] = b;
- SetRect (&r, 0, 0, pieceSize, pieceSize);
- OffsetRect (&r, h * pieceSize, v * pieceSize);
- r2 = r;
- InsetRect (&r2, 1, 1);
- SetProcRectBlob (b, DrawBoardPos, &r2, &r);
-
- /*
- * All unused postions have coordinates that sum to an
- * odd number.
- */
-
- if ((h + v) % 2 == 1)
- SetBDrawMode (b, inFullBlob, dimDraw);
- }
- }
- }
-
-
- /*
- * Make a set of checkers pieces and return the blob set handle. The first
- * blob in the set is the black piece; the second is the white piece.
- */
-
- BlobSetHandle
- MakeCheckersPieces (short pieceSize)
- {
- BlobSetHandle bSet;
- BlobHandle b;
- Rect r;
-
- bSet = NewBlobSet ();
- SetRect (&r, 0, 0, pieceSize - 1, pieceSize - 1);
- b = NewBlob (bSet, true, infiniteGlue, false, 0L);
- OpenBlob ();
- PaintRect (&r);
- PenMode (patBic);
- FrameOval (&r);
- PenNormal ();
- CloseRectBlob (b, &r, &r);
- b = NewBlob (bSet, true, infiniteGlue, false, 0L);
- OpenBlob ();
- PaintRect (&r);
- EraseOval (&r);
- CloseRectBlob (b, &r, &r);
- return (bSet);
- }
-
-
- /*
- * Given a blob handle, find the checkerboard position that corresponds to it.
- * This is used to map hits in the blob set (a list) to the position in
- * the board (a 2-d array).
- */
-
- void
- FindCheckerBoardPos (BlobHandle b, CheckerBoard *board, short *h, short *v)
- {
- short i, j;
-
- for (i = 0; i < 8; ++i)
- {
- for (j = 0; j < 8; ++j)
- {
- if ((*board)[i][j] == b)
- {
- *h = i;
- *v = j;
- return;
- }
- }
- }
- /* shouldn't ever get here */
- }
-
-
- /*
- * Check whether a checkerboard position is empty. The coordinates must be
- * legal, the position must be used in the current configuration,
- * and the position must have a piece on it.
- */
-
- Boolean
- CheckerBoardPosEmpty (CheckerBoard *board, short h, short v)
- {
- return (h >= 0 && h < 8 && v >= 0 && v < 8
- && (h + v) % 2 == 0
- && BGlob ((*board)[h][v]) == nil);
- }
-